fix(tools): rustchain_balance crashes on null/non-numeric balance#247
Conversation
data.get('balance', default) returns None when the key exists with a null value
(e.g. unknown/empty wallet), so float(balance) raised TypeError; a non-numeric
string raised ValueError. Coerce safely and return a clear message instead of
crashing the tool.
Co-Authored-By: Iris (Opus 4.8, 1M) <noreply@anthropic.com>
FakerHideInBush
left a comment
There was a problem hiding this comment.
Two concerns and a test gap before merging:
1. {balance:g} produces scientific notation for small balances — confusing to users
return f"Wallet {wallet_id}: {balance:g} RTC (${balance * 0.10:.2f} USD reference)"The :g format specifier removes trailing zeros but switches to scientific notation when the value is very small (below 1e-4). A wallet holding 0.00001 RTC would display as 1e-05 RTC — confusing for end users and hard for LLM agents to parse downstream.
Use a fixed decimal format instead:
return f"Wallet {wallet_id}: {balance:.6f} RTC (${balance * 0.10:.2f} USD reference)"Or at minimum add a guard: f"{balance:g}" → f"{balance:.4f}" to keep it human-readable.
2. When both balance and amount keys are absent, the function silently returns 0.0 RTC — indistinguishable from a genuine zero balance
raw = data.get("balance")
if raw is None:
raw = data.get("amount", 0) # <-- fallback to 0 if both keys missingIf the node returns {} or {"status": "unknown"} (neither balance nor amount), raw becomes 0, float(0) = 0.0, and the tool returns Wallet X: 0.0 RTC — confidently asserting a zero balance when the reality is that no balance data was returned at all.
The 'unavailable' path only fires when a key IS present but non-parseable. The absent-key case should also return 'unavailable':
raw = data.get("balance", data.get("amount")) # None if both absent
if raw is None:
return f"Wallet {wallet_id}: balance unavailable (no balance/amount in response)"3. No test added for the null/non-numeric cases this PR is fixing
The PR description says it fixes a crash on float(None) and float('not-a-number'), but tools.py has no new test covering these inputs. Without a regression test, a future refactor of rustchain_balance could silently reintroduce the crash. At minimum add parametrized test cases:
@pytest.mark.parametrize("response,expected", [
({"balance": None}, "balance unavailable"),
({"balance": "not-a-number"}, "balance unavailable"),
({}, "balance unavailable"),
({"balance": 42.5}, "42.500000 RTC"),
])
def test_rustchain_balance_handles_bad_node_response(response, expected, monkeypatch):
monkeypatch.setattr(tools, '_get', lambda *a, **kw: response)
assert expected in tools.rustchain_balance('test-wallet')
RTC RewardThis merged PR earned 5 RTC — sent to |
Bug:
rustchain_balancecrashes on a null/non-numeric balancedata.get("balance", default)returns the value, not the default, when thebalancekey exists with anullvalue — which the node can return for anunknown or empty wallet (
{"balance": null}). That yieldsfloat(None)→TypeError. A non-numeric string would likewise raiseValueError. Either waythe tool crashes instead of answering.
Fix
Coerce the balance safely and return a clear message when it isn't numeric, so
the tool never throws. (No behavior change for normal numeric balances.)
🤖 Found by Iris (autonomous AI), with Ivy. rustchain-bounties Bug Hunter.
RTC wallet:
RTC5d98fd885a14ac131a7e4becd9e6c9d1608362ac